# Client.py
"""
完整真实任务客户端
支持北航格式的完整API调用流程，包括真实任务数据的发送和接收处理
"""

import json
import sys
import os
import requests
import time
from datetime import datetime
from typing import Dict, Any, List, Optional
import argparse

# 添加项目根目录到路径
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from FastAPI.logger_config import get_logger

class RealMissionClient:
    """完整真实任务客户端"""
    
    def __init__(self, server_url: str = "http://localhost:8002", timeout: int = 300):
        """
        初始化客户端
        
        Args:
            server_url: 服务器地址
            timeout: 请求超时时间（秒）
        """
        self.server_url = server_url
        self.timeout = timeout
        self.api_endpoint = f"{server_url}/plan_route_beihang"
        self.logger = get_logger('real_mission_client')
        
        # 请求头
        self.headers = {
            'Content-Type': 'application/json',
            'User-Agent': 'RealMissionClient/1.0'
        }
    
    def load_mission_data(self, mission_file: str = "client/real_mission_data.json") -> Dict[str, Any]:
        """
        加载真实任务数据
        
        Args:
            mission_file: 任务数据文件路径
            
        Returns:
            Dict: 任务数据
        """
        try:
            with open(mission_file, 'r', encoding='utf-8') as f:
                mission_data = json.load(f)
            
            self.logger.info(f"成功加载任务数据: {mission_file}")
            self.logger.info(f"可用任务类型: {list(mission_data.keys())}")
            
            return mission_data
            
        except FileNotFoundError:
            self.logger.error(f"任务数据文件不存在: {mission_file}")
            raise
        except json.JSONDecodeError as e:
            self.logger.error(f"任务数据文件格式错误: {e}")
            raise
        except Exception as e:
            self.logger.error(f"加载任务数据失败: {e}")
            raise
    
    def send_mission_request(self, mission_data: Dict[str, Any]) -> Optional[Dict[str, Any]]:
        """
        发送任务规划请求
        
        Args:
            mission_data: 任务数据
            
        Returns:
            Optional[Dict]: 响应数据
        """
        try:
            self.logger.info(f"发送任务规划请求到: {self.api_endpoint}")
            self.logger.info(f"任务ID: {mission_data.get('outBizCode', 'unknown')}")
            self.logger.info(f"任务类型: {mission_data.get('routeType', 'unknown')}")
            self.logger.info(f"设备数量: {len(mission_data.get('deviceInfos', []))}")
            
            # 发送请求
            start_time = time.time()
            response = requests.post(
                self.api_endpoint,
                json=mission_data,
                headers=self.headers,
                timeout=self.timeout
            )
            
            end_time = time.time()
            elapsed_time = end_time - start_time
            
            self.logger.info(f"请求完成，耗时: {elapsed_time:.2f}秒")
            self.logger.info(f"响应状态码: {response.status_code}")
            
            if response.status_code == 200:
                result = response.json()
                self.logger.info("请求成功")
                return result
            else:
                self.logger.error(f"请求失败: {response.status_code} - {response.text}")
                return None
                
        except requests.exceptions.Timeout:
            self.logger.error(f"请求超时 (timeout={self.timeout}s)")
            return None
        except requests.exceptions.ConnectionError:
            self.logger.error("连接失败，请确保服务器正在运行")
            return None
        except Exception as e:
            self.logger.error(f"发送请求时发生错误: {e}")
            return None
    
    def process_response(self, response_data: Dict[str, Any]) -> Dict[str, Any]:
        """
        处理响应数据
        
        Args:
            response_data: 原始响应数据
            
        Returns:
            Dict: 处理后的响应数据
        """
        try:
            self.logger.info("开始处理响应数据")
            
            # 提取关键信息
            route_infos = response_data.get('routeInfos', [])
            extra_info = response_data.get('extraInfo', {})
            
            if not route_infos:
                self.logger.warning("响应中没有航线信息")
                return {
                    'status': 'warning',
                    'message': '响应中没有航线信息',
                    'data': response_data
                }
            
            # 处理每条航线
            processed_routes = []
            total_distance = 0
            total_duration = 0
            
            for i, route_info in enumerate(route_infos):
                route_points = route_info.get('routePoints', [])
                
                if not route_points:
                    self.logger.warning(f"航线 {i+1} 没有航点数据")
                    continue
                
                # 计算航线统计
                route_stats = self._calculate_route_stats(route_points, route_info)
                total_distance += route_stats['distance']
                total_duration += route_stats['duration']
                
                processed_route = {
                    'route_index': i + 1,
                    'out_biz_code': route_info.get('outBizCode', ''),
                    'start_time': route_info.get('startTime', ''),
                    'end_time': route_info.get('endTime', ''),
                    'max_alt': route_info.get('maxAlt', 0),
                    'min_alt': route_info.get('minAlt', 0),
                    'width': route_info.get('width', 0),
                    'length': route_info.get('length', 0),
                    'point_count': len(route_points),
                    'distance': route_stats['distance'],
                    'duration': route_stats['duration'],
                    'avg_speed': route_stats['avg_speed'],
                    'waypoints': self._extract_key_waypoints(route_points)
                }
                
                processed_routes.append(processed_route)
                
                self.logger.info(f"航线 {i+1}: {len(route_points)} 个航点, "
                              f"距离 {route_stats['distance']:.2f}m, "
                              f"耗时 {route_stats['duration']:.2f}s")
            
            # 汇总结果
            result = {
                'status': 'success',
                'message': f'成功处理 {len(processed_routes)} 条航线',
                'summary': {
                    'total_routes': len(processed_routes),
                    'total_distance': total_distance,
                    'total_duration': total_duration,
                    'avg_speed': total_distance / total_duration if total_duration > 0 else 0
                },
                'routes': processed_routes,
                'extra_info': extra_info,
                'raw_response': response_data
            }
            
            self.logger.info(f"处理完成: {len(processed_routes)} 条航线, "
                           f"总距离 {total_distance:.2f}m, "
                           f"总耗时 {total_duration:.2f}s")
            
            return result
            
        except Exception as e:
            self.logger.error(f"处理响应数据时发生错误: {e}")
            return {
                'status': 'error',
                'message': f'处理响应数据时发生错误: {e}',
                'data': response_data
            }
    
    def _calculate_route_stats(self, route_points: List[Dict], route_info: Dict) -> Dict[str, float]:
        """
        计算航线统计信息
        
        Args:
            route_points: 航点列表
            route_info: 航线信息
            
        Returns:
            Dict: 统计信息
        """
        try:
            if len(route_points) < 2:
                return {
                    'distance': 0,
                    'duration': 0,
                    'avg_speed': 0
                }
            
            # 计算总距离
            total_distance = 0
            for i in range(1, len(route_points)):
                p1, p2 = route_points[i-1], route_points[i]
                
                # 简化的距离计算（使用经纬度差值）
                lat_diff = p2['latitude'] - p1['latitude']
                lon_diff = p2['longitude'] - p1['longitude']
                alt_diff = p2['altitude'] - p1['altitude']
                
                # 转换为米（粗略计算）
                distance = ((lat_diff * 111000) ** 2 + (lon_diff * 111000 * 0.7) ** 2 + alt_diff ** 2) ** 0.5
                total_distance += distance
            
            # 计算总时长
            start_time = route_info.get('startTime', '')
            end_time = route_info.get('endTime', '')
            
            if start_time and end_time:
                try:
                    start_dt = datetime.fromisoformat(start_time.replace('Z', '+00:00'))
                    end_dt = datetime.fromisoformat(end_time.replace('Z', '+00:00'))
                    duration = (end_dt - start_dt).total_seconds()
                except:
                    duration = 0
            else:
                # 使用时间戳计算
                timestamps = [p.get('timestamp', 0) for p in route_points]
                if timestamps and max(timestamps) > 0:
                    duration = max(timestamps) / 1000  # 转换为秒
                else:
                    duration = 0
            
            # 计算平均速度
            avg_speed = total_distance / duration if duration > 0 else 0
            
            return {
                'distance': total_distance,
                'duration': duration,
                'avg_speed': avg_speed
            }
            
        except Exception as e:
            self.logger.warning(f"计算航线统计信息时发生错误: {e}")
            return {
                'distance': 0,
                'duration': 0,
                'avg_speed': 0
            }
    
    def _extract_key_waypoints(self, route_points: List[Dict]) -> List[Dict]:
        """
        提取关键航点
        
        Args:
            route_points: 航点列表
            
        Returns:
            List[Dict]: 关键航点
        """
        try:
            if not route_points:
                return []
            
            key_points = []
            
            # 添加起点
            key_points.append({
                'type': 'start',
                'point': route_points[0]
            })
            
            # 添加中间点（每10个点取一个）
            if len(route_points) > 20:
                step = max(1, len(route_points) // 10)
                for i in range(step, len(route_points) - step, step):
                    key_points.append({
                        'type': 'waypoint',
                        'point': route_points[i]
                    })
            
            # 添加终点
            key_points.append({
                'type': 'end',
                'point': route_points[-1]
            })
            
            return key_points
            
        except Exception as e:
            self.logger.warning(f"提取关键航点时发生错误: {e}")
            return []
    
    def save_result(self, result: Dict[str, Any], output_file: str) -> bool:
        """
        保存结果到文件
        
        Args:
            result: 结果数据
            output_file: 输出文件路径
            
        Returns:
            bool: 是否成功
        """
        try:
            with open(output_file, 'w', encoding='utf-8') as f:
                json.dump(result, f, indent=2, ensure_ascii=False)
            
            self.logger.info(f"结果已保存到: {output_file}")
            return True
            
        except Exception as e:
            self.logger.error(f"保存结果时发生错误: {e}")
            return False
    
    def run_mission(self, mission_type: str = "point_mission", 
                   mission_file: str = "real_mission_data.json",
                   output_file: str = None) -> bool:
        """
        运行完整任务流程
        
        Args:
            mission_type: 任务类型
            mission_file: 任务数据文件
            output_file: 输出文件路径
            
        Returns:
            bool: 是否成功
        """
        try:
            self.logger.info(f"开始执行任务: {mission_type}")
            
            # 加载任务数据
            mission_data = self.load_mission_data(mission_file)
            
            if mission_type not in mission_data:
                self.logger.error(f"任务类型不存在: {mission_type}")
                return False
            
            mission = mission_data[mission_type]
            
            # 发送请求
            response = self.send_mission_request(mission)
            
            if response is None:
                self.logger.error("请求失败")
                return False
            
            # 处理响应
            result = self.process_response(response)
            
            # 保存结果
            if output_file is None:
                timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
                output_file = f"mission_result_{mission_type}_{timestamp}.json"
            
            if not self.save_result(result, output_file):
                self.logger.error("保存结果失败")
                return False
            
            # 输出摘要
            self._print_summary(result)
            
            self.logger.info(f"任务执行完成: {mission_type}")
            return True
            
        except Exception as e:
            self.logger.error(f"执行任务时发生错误: {e}")
            return False
    
    def _print_summary(self, result: Dict[str, Any]):
        """
        打印结果摘要
        
        Args:
            result: 结果数据
        """
        print("\n" + "="*60)
        print("任务执行结果摘要")
        print("="*60)
        
        status = result.get('status', 'unknown')
        message = result.get('message', '')
        
        print(f"状态: {status}")
        print(f"消息: {message}")
        
        if status == 'success':
            summary = result.get('summary', {})
            print(f"航线数量: {summary.get('total_routes', 0)}")
            print(f"总距离: {summary.get('total_distance', 0):.2f}m")
            print(f"总耗时: {summary.get('total_duration', 0):.2f}s")
            print(f"平均速度: {summary.get('avg_speed', 0):.2f}m/s")
            
            routes = result.get('routes', [])
            print(f"\n航线详情:")
            for route in routes:
                print(f"  航线 {route['route_index']}: {route['point_count']} 个航点, "
                      f"{route['distance']:.2f}m, {route['duration']:.2f}s")
        
        print("="*60)

def main():
    """主函数"""
    parser = argparse.ArgumentParser(description="真实任务客户端")
    parser.add_argument("--mission", default="point_mission", 
                       choices=["point_mission", "patrol_mission"],
                       help="任务类型")
    parser.add_argument("--server", default="http://localhost:8002", help="服务器地址")
    parser.add_argument("--timeout", type=int, default=300, help="请求超时时间")
    parser.add_argument("--output", help="输出文件路径")
    
    args = parser.parse_args()
    
    # 创建客户端
    client = RealMissionClient(server_url=args.server, timeout=args.timeout)
    
    # 执行任务
    success = client.run_mission(
        mission_type=args.mission,
        output_file=args.output
    )
    
    if success:
        print(f"\n任务执行成功!")
        sys.exit(0)
    else:
        print(f"\n任务执行失败!")
        sys.exit(1)

if __name__ == "__main__":
    main()